/*
    Copyright 2006-2012 Patrik Jonsson, sunrise@familjenjonsson.org

    This file is part of Sunrise.

    Sunrise is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.

    Sunrise is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Sunrise.  If not, see <http://www.gnu.org/licenses/>.

*/

/// \file
/// Declaration of a grid class used for making images of auxiliary quantities.

#ifndef __aux_grid__
#define __aux_grid__

#include "optical.h"
#include "emission.h"

#include "mcrx-units.h"
#include "chromatic_policy.h"

namespace mcrx {
  typedef blitz::TinyVector<T_float, 10> aux_pars_type;
  class aux_pars_fields;
  template <typename,
	    template <typename> class, 
	    typename> class aux_grid;
  template<typename T> class arepo_grid;

  // typedefs for commonly used aux_grid types
  typedef aux_grid<
    adaptive_grid<
      cell_data<
	typename emitter_types<adaptive_grid, 
			       generic_chromatic_policy<aux_pars_type>,
			       local_random>::T_emitter,
	absorber<aux_pars_type> > >,
    cumulative_sampling, local_random > T_aux_adaptive_grid;
#ifdef WITH_AREPO
  typedef aux_grid<
    arepo_grid<
      cell_data<
	typename emitter_types<arepo_grid, 
			       generic_chromatic_policy<aux_pars_type>,
			       local_random>::T_emitter,
	absorber<aux_pars_type> > >,
    cumulative_sampling, local_random> T_aux_arepo_grid;
#endif
}


/** A class whose sole purpose is to contain the fields enumeration,
    which identify the fields in aux_pars_type.  */
class mcrx::aux_pars_fields {
public:
  enum fields {mass_gas=0, mass_metals=1, SFR=2, energy=3,
	       mass_stars=4, mass_metals_stars=5, L_bol=6,
	       age_m=7, age_l=8, FIR = 9};
};


/** An adaptive_grid containing emitters of the auxiliary grid quantities.
    This is used to make images of auxiliary quantities such as gas
    mass, star-formation rate and metallicity. This is also derived
    from emission, so it is its own emission object for the sources in
    the grid. */
template <typename grid_type,
	  template<typename> class sampling_policy,
	  typename rng_policy>
class mcrx::aux_grid : 
  public emission_collection<generic_chromatic_policy<aux_pars_type>,
			     sampling_policy, rng_policy>
{
public:
  typedef grid_type T_grid_impl;
  typedef typename T_grid_impl::T_data T_data;
  typedef typename T_data::T_emitter T_emitter;

  typedef typename T_emitter::T_lambda T_lambda;
  typedef typename T_grid_impl::T_cell T_cell;
  typedef typename T_grid_impl::T_cell_tracker T_cell_tracker;
  typedef typename T_grid_impl::iterator iterator;
  typedef typename T_grid_impl::const_iterator const_iterator;
  typedef typename T_emitter::T_lambda T_content;
  typedef typename T_grid_impl::T_location_request T_location_request;
  typedef typename T_grid_impl::T_location_response T_location_response;
 
private:
  /// The concrete grid object
  boost::shared_ptr<T_grid_impl> g_;

  /** Helper function to load data for adaptive_grid. Prevents
      instantiation of the function for arepo_grids. */
  template<typename T> 
  void load(boost::shared_ptr<T> g,
	    CCfits::ExtHDU& structure_hdu,
	    CCfits::ExtHDU& data_hdu,
	    bool normalize_for_emission=false) {};

  template<typename T> 
  void load(boost::shared_ptr<adaptive_grid<T> > g,
	    CCfits::ExtHDU& structure_hdu,
	    CCfits::ExtHDU& data_hdu,
	    bool normalize_for_emission=false);

  /** Helper function to load data for arepo_grid. Prevents
      instantiation of the function for adaptive_grids. */
  template<typename T>
  void load(boost::shared_ptr<T> g,
	    bool normalize_for_emission=false) {};

  template<typename T>
  void load(boost::shared_ptr<arepo_grid<T> > g,
	    bool normalize_for_emission=false);

public:
  /// Units
  T_unit_map units_;
    
  aux_grid (boost::shared_ptr<T_grid_impl> g,
	    CCfits::ExtHDU& structure_hdu,
	    CCfits::ExtHDU& data_hdu,
	    bool normalize_for_emission=false);

  aux_grid (boost::shared_ptr<T_grid_impl> g,
	    bool normalize_for_emission=false);

  /// \name  Forwarding functions for the grid interface.
  ///@{
  T_location_response 
  location_request(const T_location_request& r) const {
    return g_->location_request(r); };
  void initialize_tracker(const typename T_cell_tracker::T_code& code, 
			  const vec3d& pos,
			  T_cell_tracker& c) const {
    g_->initialize_tracker(code, pos, c); };
  T_cell_tracker locate (const vec3d &p, int thread,
			 bool accept_outside=false) {
    return g_->locate (p, thread, accept_outside);};
  std::pair<T_cell_tracker, T_float> intersection_from_without (const ray_base& ray, int thread) {
    return g_->intersection_from_without (ray, thread);};
  int get_cell_number(const T_cell_tracker& c) const {
    return g_->get_cell_number(c); };
  int n_cells() const { return g_->n_cells(); };
  std::vector<bool> get_structure () const {return g_->get_structure();};
  bool in_grid(const vec3d& p) const { return g_->in_grid(p); };
  void assert_in_grid(const vec3d& p) const {  g_->assert_in_grid(p); };
  std::vector<bool> position_ownership(std::vector<vec3d>& pos) const {
    return g_->position_ownership(pos); };
  bool shared_domain() const { return g_->shared_domain(); };

  const vec3d& getmin() const {return g_->getmin();};
  const vec3d& getmax() const {return g_->getmax();};

  const_iterator begin () const {return g_->begin ();};
  iterator begin () {return g_->begin ();};
  const_iterator end () const {return g_->end ();};
  iterator end () {return g_->end ();};
  ///@}
};



#endif

